#ifndef ENVIRONMENT_H_INCLUDED
#define ENVIRONMENT_H_INCLUDED
#include <iostream>
#include <fstream>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_statistics_double.h>
#include <gsl/gsl_sort.h>
#include "Firm.h"
#include "Bank.h"
using namespace std;

// Short declarations to allow classes to be recognized by each other
class RndGen;

// Definition of class Environment
class Environment {
    public:
    Environment (int n, double in[]); // Constructor; initialize variables, allocates memory
    void start (); // Running the simulation

    private:
    int t;
    double *input;
    int tMax, numDstr, numUstr, numBanks; // Parameters of the simulation
    DownstreamFirm* dFirmsArray; // Array of downstream firms
    UpstreamFirm* uFirmsArray; // Array of upstream firms
    Bank* banksArray; // Array of banks
    void step (); // One time step on the simulation
    void printOutput (); // Print desired output to data files

    // Auxiliar variables
    RndGen* rndGen;
    double rndPrice;
    int rndAgent, ustrToLook, banksToLook;
    double probRandom;
    double eps;

    // Output-related variables
    double dstrAggrProd, dstrAvgProfit, dstrFail,
           bankAvgIR, bankAvgBD, bankFail, bankEntropy;
    ofstream dstrAggrProdOut, dstrSizeDistOut, dstrAvgProfitOut, dstrFailOut,
             bankAvgIROut, bankIRDistOut, bankAvgBDOut, bankFailOut, bankEntropyOut;
};

// Definition of auxiliar class RndGen
class RndGen {
    public:
    RndGen(); // Constructor
    const gsl_rng_type *T;
    gsl_rng *r;
    double getRndDouble (double minsp, double maxsp); // Returns double between minsp and maxsp
    int getRndInt (int min, int max); // Returns int between min and max
};

#endif // ENVIRONMENT_H_INCLUDED
